/****************************************************************************
*                                                                           *
* scatmatrix.h									                            *
*                                                                           *
* ALaRI 2008												                *
*                                                                           *
****************************************************************************/
#pragma once

#if !defined(__SCATMATRIX_H)
#define __SCATMATRIX_H

/****************************************************************************
* Includes										                            *
****************************************************************************/
#include <complex>
#include "scatblock.h"
#include "../../common/defs.h"

/****************************************************************************
* Forward declarations							                            *
****************************************************************************/
class CScatMatrix;
class CScatMatrixL0;
class CScatMatrixLP;
class CScatMatrixLPT;

/****************************************************************************
* CScatMatrix - scattering matrix											*
****************************************************************************/
class CScatMatrix
{
public:

	/****************************************************************************
	* Blocks in the matrix (all 16 plus 4 block I Matrix)						*
	* !!!NOTE: don't change numbers of enum!									*
	****************************************************************************/
	enum eBlock
	{
		// blocks for mapping ...
		eBlock_N2N = 0,
		eBlock_N2E = 1,
		eBlock_N2S = 2,
		eBlock_N2W = 3,
		eBlock_E2E = 4,
		eBlock_E2S = 5,
		eBlock_E2W = 6,
		eBlock_S2S = 7,
		eBlock_S2W = 8,
		eBlock_W2W = 9,
		// I matrix
		eBlock_ILT = 10,
		eBlock_IRB = 11,
		eBlock_IRT = 12,
		// these are substituted by above but transpose is applied
		eBlock_E2N,
		eBlock_S2N,
		eBlock_S2E,
		eBlock_W2N,
		eBlock_W2E,
		eBlock_W2S,
		// I matrix
		eBlock_ILB
	};

	/****************************************************************************
	* Destruction																*
	****************************************************************************/
	virtual ~CScatMatrix() {}

	/****************************************************************************
	* Overrides																	*
	****************************************************************************/
	// width and height in pixels
	virtual int getWidth() const = 0;
	virtual int getHeight() const = 0;
	// child matrices
	virtual const CScatMatrix* getLOrT() const = 0;
	virtual const CScatMatrix* getROrB() const = 0;
	// get the block of the matrix for processing
	virtual const CScatBlock* getBlock(eBlock nBlock, bool bCreateIfNotThere) const = 0;
	// get matrix of transformed SPACE!
	virtual const CScatMatrix* getTransformed(
		CTransform::eTransform nTransform, bool bCreateIfNotThere) const = 0;
};

/****************************************************************************
* CScatMatrixL0 - scattering matrix (level 0)								*
****************************************************************************/
class CScatMatrixL0 : public CScatMatrix
{
public:

	/****************************************************************************
	* Public virtual overrides													*
	****************************************************************************/
	virtual int getWidth() const;
	virtual int getHeight() const;
	virtual const CScatMatrix* getLOrT() const;
	virtual const CScatMatrix* getROrB() const;
	virtual const CScatBlock* getBlock(eBlock nBlock, bool bCreateIfNotThere) const;
	virtual const CScatMatrix* getTransformed(
		CTransform::eTransform nTransform, bool bCreateIfNotThere) const;

	/****************************************************************************
	* Construction/Destruction											*
	****************************************************************************/
	CScatMatrixL0(const std::complex<float>& fltThetta01, const std::complex<float>&  fltThetta02);

protected:

	/****************************************************************************
	* Private variables															*
	****************************************************************************/
	CScatBlockL0	m_fltThetta01;
	CScatBlockL0	m_fltThetta02;
};

/****************************************************************************
* CScatMatrixLP - scattering matrix (level+)								*
****************************************************************************/
class CScatMatrixLP : public CScatMatrix
{
public:

	/****************************************************************************
	* Overrides																	*
	****************************************************************************/
	virtual int getWidth() const;
	virtual int getHeight() const;
	virtual const CScatMatrix* getLOrT() const;
	virtual const CScatMatrix* getROrB() const;
	virtual const CScatBlock* getBlock(eBlock nBlock, bool bCreateIfNotThere) const;
	virtual const CScatMatrix* getTransformed(
		CTransform::eTransform nTransform, bool bCreateIfNotThere) const;

	/****************************************************************************
	* Construction																*
	****************************************************************************/
	CScatMatrixLP(const CScatMatrix *pLOrT, const CScatMatrix *pROrB, bool bHorizontal);
	~CScatMatrixLP();

protected:

	/****************************************************************************
	* Protected helpers															*
	****************************************************************************/
	void constructBlockLP(CScatMatrix::eBlock nBlock);
	void computeBlockN2X();
	void computeBlockE2X();
	void computeBlockS2X();
	void computeBlockW2W();
	void computeBlockILT();
	void computeBlockIRB();
	void computeBlockIRT();
	// this function multiplies 2 square matrixes and returns result
	// which is known to be always symetric. If pL and pR are producing
	// non symetric matrix the result will be invalid.
	static CScatBlockLP* symetricMultiply(const CScatBlock *pL, const CScatBlock *pR);
	// this function performs simple multiplication of two blocks
	static CScatBlockLP* simpleMultiply(const CScatBlock *pL, const CScatBlock *pR);
	// this function is rather complicated. It is used to compute symetric blocks
	// of the exchage scattering matrix where the block is a longer edge of the
	// compound node. For example: in horizontal case - NN and SS are 2x2 blocks.
	// block paramters are as follows:
	//								| B1 + B2 * B3,		B2 * B4		|
	// result = symetric matrix of	| transp(B2 * B4),	B5 + B6 * B7|
	static CScatBlockLP* computeSymetricBlock2x2(const CScatBlock *pB1,
		const CScatBlock *pB2, const CScatBlock *pB3, const CScatBlock *pB4,
		const CScatBlock *pB5, const CScatBlock *pB6, const CScatBlock *pB7);
	// same as above - formula: | B1 + B2 * B3 |
	static CScatBlockLP* computeSymetricBlock1x1(
		const CScatBlock *pB1, const CScatBlock *pB2, const CScatBlock *pB3);
	// this function also computes exchange scattering matrix block but these blocks
	// are not symetric. The formula is: | B1 * B2, B3 + B1 * B4 |
	static CScatBlockLP* computeNormalBlock2x1(const CScatBlock *pB1,
		const CScatBlock *pB2, const CScatBlock *pB3, const CScatBlock *pB4);
	// same as above - formula: | B1 + B2 * B3,	B2 * B4 |
	static CScatBlockLP* computeNormalBlock2x1F(const CScatBlock *pB1,
		const CScatBlock *pB2, const CScatBlock *pB3, const CScatBlock *pB4);
	// same as above - formula:	| B1 + B2 * B3	|
	//							| B4 * B5		|
	static CScatBlockLP* computeNormalBlock1x2(
		const CScatBlock *pB1, const CScatBlock *pB2, const CScatBlock *pB3,
		const CScatBlock *pB4, const CScatBlock *pB5);
	// same as above - formula:	| B1 * B2		|
	//							| B3 + B4 * B5	|
	static CScatBlockLP* computeNormalBlock1x2F(
		const CScatBlock *pB1, const CScatBlock *pB2, const CScatBlock *pB3,
		const CScatBlock *pB4, const CScatBlock *pB5);
	// some as above - the formula is:
	// | B1 + B2 * B3,	B2 * B4			|
	// | B5 * B6,		B7 + B5 * B8	|
	static CScatBlockLP* computeNormalBlock2x2(
		const CScatBlock *pB1, const CScatBlock *pB2, const CScatBlock *pB3,
		const CScatBlock *pB4, const CScatBlock *pB5, const CScatBlock *pB6,
		const CScatBlock *pB7, const CScatBlock *pB8);

	/****************************************************************************
	* Protected data															*
	****************************************************************************/
	// child matrices
	const CScatMatrix	*m_pLOrT;
	const CScatMatrix	*m_pROrB;
	// width and height of the matrix in pixels
	int					m_nWidth;
	int					m_nHeight;
	// array of matrix transforms
	CScatMatrixLPT*		m_rgnpTransforms[CTransform::eTransform_count - 1];
	// in any matrix we have only 10 unique blocks of data + 3 blocks for I matrix
	// - others are just transforms
	CScatBlockLP*		m_prgnBlockLPs[13];
};

/****************************************************************************
* CScatMatrixLP - private class for LP matrix								*
****************************************************************************/
class CScatMatrixLPT : public CScatMatrix
{
public:

	/****************************************************************************
	* Overrides																	*
	****************************************************************************/
	virtual int getWidth() const;
	virtual int getHeight() const;
	virtual const CScatMatrix* getLOrT() const;
	virtual const CScatMatrix* getROrB() const;
	virtual const CScatBlock* getBlock(eBlock nBlock, bool bCreateIfNotThere) const;
	virtual const CScatMatrix* getTransformed(
		CTransform::eTransform nTransform, bool bCreateIfNotThere) const;

private:

	/****************************************************************************
	* Construction																*
	****************************************************************************/
	CScatMatrixLPT(CScatMatrixLP *pOwner, CTransform::eTransform nTransform);

	/****************************************************************************
	* Constructed and managed by CScatMatrixLP									*
	****************************************************************************/
	friend class CScatMatrixLP;

	/****************************************************************************
	* Protected data															*
	****************************************************************************/
	CScatMatrixLP			*m_pOwner;
	CTransform::eTransform	m_nTransform;
};

#endif /* __SCATMATRIX_H */

/****************************************************************************
* End of file																*
****************************************************************************/
